﻿using System.Collections.Generic;
using System.Linq;
using Foothill.Common;

namespace Foothill.Model
{
    public class ForSaleAdAdvancedSearchParameter
    {
        private Dictionary<int, bool> _selectedLocationIdLookup;
        private IList<MakeAndModelSelection> _selectedMakeAndModelIdLookup;
        private IList<int> _selectedMileageGroupIdList;
        private IList<int> _selectedYearAgeGroupIdList;

        private IList<RangeBasedAdSearchCriteria> _rangeBasedCriterias;
      
        public bool IsDefault { set; get; }

        public bool WithPhotosOnly { set; get; }
        public bool AllLocationSelected { set; get; }
        public bool IncludeAllMakes { set; get; }

        public IList<MakeAndModelSelection> SelectedMakeAndModelIdLookup
        {
            get
            {
                return _selectedMakeAndModelIdLookup;
            }
        }

        public List<int> LocationIdList
        {
            get
            {
                List<int> result = new List<int>();
                foreach (var pair in _selectedLocationIdLookup.Where(p => p.Value))
                {
                    result.Add(pair.Key);
                }

                return result;
            }
        }

        public IList<int> SelectedMileageGroupIdList
        {
            get
            {
                return _selectedMileageGroupIdList;
            }
        }

        public IList<int> SelectedYearAgeGroupIdList
        {
            get
            {
                return _selectedYearAgeGroupIdList;
            }
        }

        // owner or dealer or both
        public int ListingTypeId { set; get; }
        // new or used or both
        public int ConditionId { set; get; } 
        // auto or manual or both
        public int TransmissionTypeId { set; get; }

        public int PageSize { set; get; }
        public int PageNum { set; get; }

        public OrderByItems OrderByItem { set; get; }
        public fhSortDirection SortDirection { set; get; }

        public List<AdCategorySelectItem> FilterList { set; get; }

        // param less constructor should only be used for tests
        internal ForSaleAdAdvancedSearchParameter()
        {
            FilterList = new List<AdCategorySelectItem>();
            _rangeBasedCriterias = new List<RangeBasedAdSearchCriteria>();
            _selectedLocationIdLookup = new Dictionary<int, bool>();
            _selectedMakeAndModelIdLookup = new List<MakeAndModelSelection>();
            _selectedMileageGroupIdList = new List<int>();
            _selectedYearAgeGroupIdList = new List<int>();
            AllLocationSelected = true;
            IncludeAllMakes = false;
        }

        public ForSaleAdAdvancedSearchParameter(IList<int> cityIdList)
        {
            TransmissionTypeId = (int)TransmissionType.Both;
            ConditionId = (int)VehicleCondition.Both;
            ListingTypeId = (int)ListingTypes.Both;

            FilterList = new List<AdCategorySelectItem>();
            AllLocationSelected = true;
            IncludeAllMakes = false;

            _selectedLocationIdLookup = new Dictionary<int, bool>();
            _selectedMakeAndModelIdLookup = new List<MakeAndModelSelection>();
            _selectedMileageGroupIdList = new List<int>();
            _selectedYearAgeGroupIdList = new List<int>();
            _rangeBasedCriterias = new List<RangeBasedAdSearchCriteria>();
            
            // by default, select all the locations
            foreach (var id in cityIdList)
            {
                _selectedLocationIdLookup.Add(id, true);
            }
        }

        public void AddSelectedCityIdList(IList<int> selectedCityIdList)
        {
            for (int i = 0; i < _selectedLocationIdLookup.Count; ++i)
            {
                _selectedLocationIdLookup[i] = selectedCityIdList.Contains(i);
            }
        }

        public void AddFilterItem(AdCategorySelectItem newItem)
        {
            switch (newItem.Category)
            {
                case AdListCategory.Condition:
                    AddVehicleConditionFilterItem(newItem);
                    break;
                case AdListCategory.ListingType:
                    AddListingTypeFileterItem(newItem);
                    break;
                case AdListCategory.City:
                    AddCityFilterItem(newItem);
                    break;
                case AdListCategory.Make:
                    AddMakeFilterItem(newItem);
                    break;
                case AdListCategory.TransmissionType:
                    AddTransmissionTypeFilterItem(newItem);
                    break;
                case AdListCategory.Mileage:
                    AddMileageFilterItem(newItem);
                    break;
                case AdListCategory.YearAge:
                    AddYearAgeFilterItem(newItem);
                    break;
            }
        }

        public bool ContainRangeBasedCriteria(RangeBasedCriteria criteriaType)
        {
            return _rangeBasedCriterias.SingleOrDefault(p => p.CriteriaType == criteriaType) != null;
        }

        public bool ContainRangeBasedCriteria(RangeBasedCriteria criteriaType, out int min, out int max)
        {
            RangeBasedAdSearchCriteria criteria = _rangeBasedCriterias.SingleOrDefault(p => p.CriteriaType == criteriaType);
            min = 0;
            max = 0;
            
            if (criteria != null)
            {
                min = criteria.Min;
                max = criteria.Max;
                return true;
            }

            return false;
        }

        public bool TryGetRangeBasedCriteria(RangeBasedCriteria criteriaType, out RangeBasedAdSearchCriteria criteria)
        {
            criteria = _rangeBasedCriterias.SingleOrDefault(p => p.CriteriaType == criteriaType);
            return criteria != null;
        }

        public void AddRangeBasedAdSearchCriteria(RangeBasedCriteria criteriaType, int minVal, int maxVal)
        {
            RemoveRangeBasedAdSearchCriteria(criteriaType);
            _rangeBasedCriterias.Add(new RangeBasedAdSearchCriteria(criteriaType, minVal, maxVal));
        }

        public void AddRangeBasedAdSearchCriteria(RangeBasedAdSearchCriteria criteria)
        {
            RemoveRangeBasedAdSearchCriteria(criteria.CriteriaType);
            _rangeBasedCriterias.Add(criteria);
        }
        
        public void RemoveRangeBasedAdSearchCriteria(RangeBasedCriteria criteriaType)
        {
            RangeBasedAdSearchCriteria theOne = _rangeBasedCriterias.FirstOrDefault(c => c.CriteriaType == criteriaType);
            if (theOne != null)
            {
                _rangeBasedCriterias.Remove(theOne);
            }
        }

        public void AddMakeAndModel(int makeId, int modelId)
        {
            MakeAndModelSelection item = _selectedMakeAndModelIdLookup.SingleOrDefault(i => i.MakeId == makeId);

            if (item != null)
            {
                // modify the existing
                item.ModelId = modelId;
                item.Selected = true;
            }
            else
            {
                // create a new one
                _selectedMakeAndModelIdLookup.Add(new MakeAndModelSelection{ MakeId = makeId, ModelId = modelId, Selected = true});
            }
        }

        // return a list of id of specific models.  
        public void GetSelectedMakeAndModelIdList(out IList<int> makeIdList, out IList<int> modelIdList)
        {
            modelIdList = new List<int>();
            makeIdList = new List<int>();

            foreach (MakeAndModelSelection makeAndModelSel in _selectedMakeAndModelIdLookup)
            {
                if (!makeAndModelSel.Selected)
                {
                    continue;
                }
                
                if (makeAndModelSel.ModelId != GlobalValues.AllModelId)
                {
                    // a specific model
                    modelIdList.Add(makeAndModelSel.ModelId);
                }
                else
                {
                    // all models for a make
                    makeIdList.Add(makeAndModelSel.MakeId);
                }
            }
        }

        private void AddTransmissionTypeFilterItem(AdCategorySelectItem newItem)
        {
            if (TransmissionTypeId == (int)TransmissionType.Both && newItem.Action == SelectItemAction.Add)
            {
                TransmissionTypeId = newItem.SelectedIdValue;
            }
            else if (newItem.Action == SelectItemAction.Add && TransmissionTypeId != newItem.SelectedIdValue)
            {
                TransmissionTypeId = (int)TransmissionType.Both;
            }
            else if (TransmissionTypeId == (int)TransmissionType.Both && newItem.Action == SelectItemAction.Remove)
            {
                TransmissionTypeId = GetTheOtherTransmissionTypeId((TransmissionType)newItem.SelectedIdValue);
            }
            else if (TransmissionTypeId == (int)newItem.SelectedIdValue && newItem.Action == SelectItemAction.Remove)
            {
                TransmissionTypeId = (int)TransmissionType.Both;
            }
        }

        private void AddVehicleConditionFilterItem(AdCategorySelectItem newItem)
        {
            if (ConditionId == (int)VehicleCondition.Both && newItem.Action == SelectItemAction.Add)
            {
                ConditionId = newItem.SelectedIdValue; 
            }
            else if (newItem.Action == SelectItemAction.Add && ConditionId != newItem.SelectedIdValue)
            {
                ConditionId = (int)VehicleCondition.Both;
            }
            else if (ConditionId == (int)VehicleCondition.Both && newItem.Action == SelectItemAction.Remove)
            {
                ConditionId = GetTheOtherConditionId((VehicleCondition)newItem.SelectedIdValue);
            }
            else if (ConditionId == (int)newItem.SelectedIdValue && newItem.Action == SelectItemAction.Remove)
            {
                ConditionId = (int)VehicleCondition.Both;
            }
        }

        private void AddListingTypeFileterItem(AdCategorySelectItem newItem)
        {
            if (ListingTypeId == (int)ListingTypes.Both && newItem.Action == SelectItemAction.Add)
            {
                ListingTypeId = newItem.SelectedIdValue;
            }
            else if (ListingTypeId != newItem.SelectedIdValue && newItem.Action == SelectItemAction.Add)
            {
                ListingTypeId = (int)ListingTypes.Both;
            }
            else if (ListingTypeId == (int)ListingTypes.Both && newItem.Action == SelectItemAction.Remove)
            {
                ListingTypeId = GetTheOtherListingTypeId((ListingTypes)newItem.SelectedIdValue);
            }
            else if (ListingTypeId == (int)newItem.SelectedIdValue && newItem.Action == SelectItemAction.Remove)
            {
                ListingTypeId = (int)ListingTypes.Both;
            }
        }

        private void AddCityFilterItem(AdCategorySelectItem newItem)
        {
            if (AllLocationSelected && newItem.Action == SelectItemAction.Add)
            {
                AllLocationSelected = false;

                // first clear all the selection
                Dictionary<int, bool> temp = new Dictionary<int, bool>();

                foreach (var pair in _selectedLocationIdLookup)
                {
                    temp.Add(pair.Key, false);
                }

                _selectedLocationIdLookup = temp;
                
                _selectedLocationIdLookup[newItem.SelectedIdValue] = true;
            }
            else if (AllLocationSelected && newItem.Action == SelectItemAction.Remove)
            {
                AllLocationSelected = false;

                // first set all the selection
                Dictionary<int, bool> temp = new Dictionary<int, bool>();

                foreach (var pair in _selectedLocationIdLookup)
                {
                    temp.Add(pair.Key, true);
                }

                _selectedLocationIdLookup = temp;

                _selectedLocationIdLookup[newItem.SelectedIdValue] = false;
            }
            else if (newItem.Action == SelectItemAction.Remove)
            {
                _selectedLocationIdLookup[newItem.SelectedIdValue] = false;

                // if none of the city is selected, set all selected to true
                if (_selectedLocationIdLookup.Values.Any(k => k) == false)
                {
                    AllLocationSelected = true;
                }
            }
            else if (newItem.Action == SelectItemAction.Add)
            {
                _selectedLocationIdLookup[newItem.SelectedIdValue] = true;

                // if all the cities are selected, changed the AllLocationSelected
                if (_selectedLocationIdLookup.Values.Any(k => !k) == false)
                {
                    AllLocationSelected = true;
                }
            }
        }

        private void AddMakeFilterItem(AdCategorySelectItem newItem)
        {
            MakeAndModelSelection item = _selectedMakeAndModelIdLookup.SingleOrDefault(i => i.MakeId == newItem.SelectedIdValue);

            if (item != null)
            {
                item.Selected = (newItem.Action == SelectItemAction.Add);
            }
            else
            {
                _selectedMakeAndModelIdLookup.Add(new MakeAndModelSelection { MakeId = newItem.SelectedIdValue, ModelId = GlobalValues.AllModelId, Selected = true});
            }
        }

        private void AddMileageFilterItem(AdCategorySelectItem newItem)
        {
            if (newItem.Action == SelectItemAction.Remove)
            {
                _selectedMileageGroupIdList.Remove(newItem.SelectedIdValue);
            }
            else
            {
                _selectedMileageGroupIdList.Add(newItem.SelectedIdValue);
            }
        }

        private void AddYearAgeFilterItem(AdCategorySelectItem newItem)
        {
            if (newItem.Action == SelectItemAction.Remove)
            {
                _selectedYearAgeGroupIdList.Remove(newItem.SelectedIdValue);
            }
            else
            {
                _selectedYearAgeGroupIdList.Add(newItem.SelectedIdValue);
            }
        }

        private int GetTheOtherConditionId(VehicleCondition condition)
        {
            return (int)(condition == VehicleCondition.New ? VehicleCondition.Used : VehicleCondition.New);
        }

        private int GetTheOtherListingTypeId(ListingTypes type)
        {
            return (int)(type == ListingTypes.Dealer ? ListingTypes.Owner : ListingTypes.Dealer);
        }

        private int GetTheOtherTransmissionTypeId(TransmissionType tranType)
        {
            return (int)(tranType == TransmissionType.Automatic ? TransmissionType.Manual : TransmissionType.Automatic);
        }
    }
}
